# -*- coding: utf-8 -*-
# @Time    : 2024/6/27 13:24
# @Author  : yujiahao
# @File    : 19_pandas_excel.py
# @description: Pandas Excel 读写操作

"""
Excel 是由微软公司开发的办公软件之一，它在日常工作中得到了广泛的应用。在数据量较少的情况下，Excel 对于数据的处理、分析、可视化有其独特的优势，
因此可以显著提升您的工作效率。但是，当数据量非常大时，Excel 的劣势就暴露出来了，比如，操作重复、数据分析难等问题。
Pandas 提供了操作 Excel 文件的函数，可以很方便地处理 Excel 表格。

Pandas DataFrame.to_excel() 函数的常用参数说明如下：

参数名称        描述说明
excel_writer    文件路径或者 ExcelWriter 对象。
sheet_name      指定要写入数据的工作表名称。
na_rep          缺失值的表示形式。
float_format    用于格式化浮点数字符串的可选参数。
columns         指要写入的列。
header          写出每一列的名称，如果给出的是字符串列表，则表示列的别名。
index           表示要写入的索引。
index_label     引用索引列的列标签。如果未指定，并且 header 和 index 均为 True，则使用索引名称。如果 DataFrame 使用 MultiIndex，则需要给出一个序列。
startrow        初始写入的行位置，默认值为 0。表示引用左上角的行单元格来存储 DataFrame。
startcol        初始写入的列位置，默认值为 0。表示引用左上角的列单元格来存储 DataFrame。
engine          用于指定要使用的引擎，可以是 openpyxl 或 xlsxwriter。
merge_cells     是否合并单元格。
encoding        指定编码类型。
inf_rep         替换无穷大的字符串。
verbose         是否打印信息。
freeze_panes    冻结窗格。可以是一个元组，例如 (1, 0) 表示冻结第一行。


"""

import pandas as pd
from openpyxl import load_workbook
from openpyxl.styles import Font


# todo 1、写入Excel
def pandas_write_excel(file_output_path_excel):
    # 基础用法：写入单个 DataFrame
    data = {'Name': ['Smith', 'Parker'], 'ID': [101, 102], 'Language': ['Python', 'JavaScript']}
    df = pd.DataFrame(data)

    # 创建一个 ExcelWriter 对象，用于写入 Excel 文件
    writer = pd.ExcelWriter(file_output_path_excel, engine='openpyxl')

    # 将 DataFrame 写入 Excel 文件
    df.to_excel(writer, index=False, sheet_name='Sheet1')

    # 关闭 ExcelWriter 对象，确保数据写入文件
    writer.close()
    print(f"基础用法：DataFrame 已写入 {file_output_path_excel}")

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 进阶用法：写入多个工作表
    data1 = {'Name': ['Jones', 'Brown'], 'ID': [103, 104], 'Language': ['Java', 'C#']}
    df1 = pd.DataFrame(data1)

    # 使用 'openpyxl' 引擎以追加模式打开现有的 Excel 文件
    with pd.ExcelWriter(file_output_path_excel, engine='openpyxl', mode='a') as writer:
        # 将第二个 DataFrame 写入新的工作表
        df1.to_excel(writer, sheet_name='Sheet2', index=False)

    print(f"进阶用法：多个工作表已写入 {file_output_path_excel}")

    # 高级用法：添加格式化
    with pd.ExcelWriter(file_output_path_excel, engine='openpyxl', mode='a') as writer:
        # 将第一个 DataFrame 再次写入，放在一个新的工作表中
        df.to_excel(writer, sheet_name='FormattedSheet', index=False)

        # 获取工作簿对象
        workbook = writer.book

        # 获取刚刚写入的工作表对象
        worksheet = writer.sheets['FormattedSheet']

        # 设置工作表中列的宽度
        worksheet.column_dimensions['A'].width = 20
        worksheet.column_dimensions['B'].width = 10
        worksheet.column_dimensions['C'].width = 20

        # 创建一个字体对象，设置为粗体和红色
        font = Font(bold=True, color="FF0000")

        # 将字体应用到第一行的所有单元格
        for cell in worksheet["1:1"]:
            cell.font = font

    print(f"高级用法：格式化已应用于 {file_output_path_excel}")


# todo 2、读Excel
def pandas_read_excel(file_input_path_excel):
    # 基础用法：读取单个工作表，默认情况下只会读取 Excel 文件中的第一个工作表
    df = pd.read_excel(file_input_path_excel)
    print(f"基础用法：从 {file_input_path_excel} 读取的 DataFrame：")
    print(df)

    # 进阶用法：读取特定工作表
    df_sheet2 = pd.read_excel(file_input_path_excel, sheet_name='Sheet2')
    print(f"进阶用法：从 {file_input_path_excel} 的 Sheet2 读取的 DataFrame：")
    print(df_sheet2)

    # 高级用法：读取特定列
    df_columns = pd.read_excel(file_input_path_excel, usecols=['Name', 'Language'])
    print(f"高级用法：从 {file_input_path_excel} 读取的特定列 DataFrame：")
    print(df_columns)

    # 读取 Excel 数据，选择前两列作为索引列，选择前三列数据
    df_indexed = pd.read_excel(file_input_path_excel, index_col=[0, 1], usecols=[0, 1, 2])
    # 处理未命名列，固定用法
    df_indexed.columns = df_indexed.columns.str.replace('Unnamed.*', 'col_label')
    print(f"读取 Excel 数据并处理未命名列后的 DataFrame：")
    print(df_indexed)


def main():
    file_output_path_excel = '../../../output/ruyi.xlsx'
    file_input_path_excel = file_output_path_excel

    # 写入 Excel
    pandas_write_excel(file_output_path_excel)

    # 读取 Excel
    pandas_read_excel(file_input_path_excel)


if __name__ == '__main__':
    main()
